home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / gus / mikmod2.zip / MIKMOD.C next >
C/C++ Source or Header  |  1993-12-03  |  7KB  |  358 lines

  1. /*
  2.     MIKMOD.C    Programmed by MikMak of Unicorn Design
  3. */
  4.  
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <fcntl.h>
  8. #include <io.h>
  9. #include <dos.h>
  10. #include <string.h>
  11. #include <alloc.h>
  12. #include <conio.h>
  13.  
  14. #include "forte.h"
  15. #include "gf1proto.h"
  16. #include "extern.h"
  17. #include "ultraerr.h"
  18. #include "modload.h"
  19. #include "modplay.h"
  20. #include "mytypes.h"
  21.  
  22. ULTRA_CFG config;
  23.  
  24.  
  25. ULONG Ultra[31];
  26.  
  27. /* Ultra[] holds the sample dram adresses
  28.    of the 31 samples of a module */
  29.  
  30.  
  31.  
  32. void SetBPM(int bpm)
  33. {
  34.     /* The player routine has to be called (bpm*50)/125 times a second,
  35.        so the interval between calls takes 125/(bpm*50) seconds (amazing!).
  36.  
  37.        The Timer1 handler has a resolution of 160 microseconds.
  38.  
  39.        So the timer value to program:
  40.  
  41.        (125/(bpm*50)) / 1.6e-4 = 15625/bpm
  42.     */
  43.  
  44.     UltraStartTimer(1,15625/bpm);
  45. }
  46.  
  47.  
  48.  
  49.  
  50. void HandleTimer1()
  51. {
  52.     int t;
  53.     SAMPLEINFO *d;
  54.     UWORD period,vol;
  55.     ULONG base;
  56.     static int odd=0;
  57.  
  58.     /* Do not service the odd calls to this handler .. This
  59.        effectively makes this a 2*80=160 microsecond handler */
  60.  
  61.     if(odd^=1) return;
  62.  
  63.     MP_HandleTick();    // Call the player routine
  64.  
  65.     for(t=0;t<ml_numchn;t++){    // for each channel
  66.  
  67.         /* get sample period and volume */
  68.  
  69.         period=mp_audio[t].period;
  70.         if(period<100) period=100;        // limit the period value
  71.         if(period>8000) period=8000;
  72.  
  73.         vol=((UWORD)511*mp_audio[t].volume)/64;
  74.  
  75.         UltraSetFrequency(t,(ULONG)3579546/period);
  76.         UltraVectorLinearVolume(t,vol,60,0);
  77.  
  78.         // Check if the sample has to be restarted
  79.  
  80.         if(mp_audio[t].kick){
  81.  
  82.             // Get sample dram address
  83.  
  84.             base=Ultra[mp_audio[t].sample];
  85.  
  86.             UltraVoiceOff(t,0);    // <- This seems to be neccecary
  87.  
  88.             if(mp_audio[t].loop<mp_audio[t].size){
  89.  
  90.                 // Start a looping sample, start at volume 0
  91.  
  92.                 UltraSetLinearVolume(t,0);
  93.  
  94.                 // Then, a fast ramp to current volume
  95.  
  96.                 UltraVectorLinearVolume(t,vol,60,0);
  97.  
  98.                 UltraStartVoice(t,
  99.                                 base+mp_audio[t].start,
  100.                                 base+mp_audio[t].loop,
  101.                                 base+mp_audio[t].size,0x8);
  102.             }
  103.             else{
  104.  
  105.                 // Start a one-shot sample
  106.  
  107.                 UltraSetLinearVolume(t,0);
  108.                 UltraVectorLinearVolume(t,vol,60,0);
  109.  
  110.                 UltraStartVoice(t,
  111.                                 base+mp_audio[t].start,
  112.                                 base+mp_audio[t].start,
  113.                                 base+mp_audio[t].size,0);
  114.             }
  115.             mp_audio[t].kick=0;
  116.         }
  117.     }
  118.     SetBPM(mp_bpm);        // Update beats-per-minute
  119. }
  120.  
  121.  
  122.  
  123.  
  124. int UltraGetCfg(ULTRA_CFG *config)
  125. {
  126.     char *ptr;
  127.  
  128.     config->base_port = 0x220;
  129.     config->dram_dma_chan = 1;
  130.     config->adc_dma_chan = 1;
  131.     config->gf1_irq_num = 11;
  132.     config->midi_irq_num = 5;
  133.  
  134.     if((ptr=getenv("ULTRASND"))==NULL) return FALSE;
  135.  
  136.     if(sscanf(ptr,"%x,%d,%d,%d,%d"
  137.                 ,&config->base_port,
  138.                 &config->dram_dma_chan,
  139.                 &config->adc_dma_chan,
  140.                 &config->gf1_irq_num,
  141.                 &config->midi_irq_num)!=5) return FALSE;
  142.  
  143.     return(TRUE);
  144. }
  145.  
  146.  
  147.  
  148.  
  149. void UltraDownloadX(UBYTE *data_ptr,UBYTE control,ULONG dram_loc,UWORD len,int wait)
  150. /*
  151.     Identical to UltraDownLoad() except this one handles
  152.     dram_loc's that    aren't on a 32-byte boundary.
  153. */
  154. {
  155.     /* Dram location not on a 32 byte boundary ? */
  156.  
  157.     while(len>0 && (dram_loc&31)){
  158.  
  159.         /* Slowly 'poke' the odd
  160.            samples into gus dram */
  161.  
  162.         UltraPokeData(config.base_port,dram_loc,*data_ptr);
  163.  
  164.         data_ptr++;
  165.         dram_loc++;
  166.         len--;
  167.     }
  168.  
  169.     // The rest goes fast...
  170.  
  171.     if(len>0) UltraDownload(data_ptr,control,dram_loc,len,wait);
  172. }
  173.  
  174.  
  175.  
  176.  
  177.  
  178. ULONG UltraFileload(FILE *fp,UBYTE control,ULONG dram_loc,ULONG size)
  179. /*
  180.     This function directly loads data from a file into gus dram.
  181.     returns the number of bytes actually loaded.
  182. */
  183. {
  184.     ULONG todo,total=0,done;
  185.     char *buffer;
  186.  
  187.     if((buffer=malloc(8000))==NULL) return 0;
  188.  
  189.     do{
  190.         todo=(size>8000)?8000:size;
  191.  
  192.         done=fread(buffer,1,todo,fp);
  193.  
  194.         UltraDownloadX(buffer,control,dram_loc,done,TRUE);
  195.  
  196.         total+=done;
  197.         dram_loc+=done;
  198.         size-=done;
  199.  
  200.     } while( size>0 && (done==todo) );
  201.  
  202.     free(buffer);
  203.  
  204.     return total;
  205. }
  206.  
  207.  
  208. UBYTE UltraPeek(ULONG address)
  209. {
  210.     return(UltraPeekData(config.base_port,address));
  211. }
  212.  
  213.  
  214. void UltraPoke(ULONG address,UBYTE val)
  215. {
  216.     UltraPokeData(config.base_port,address,val);
  217. }
  218.  
  219.  
  220.  
  221. int MyLoader(int samplenr,FILE *fp,ULONG ssize)
  222. /*
  223.     callback routine for the MODLOAD module.
  224.  
  225.     samplenr    :Number of the sample that is being loaded
  226.     fp            :file ptr to that sample
  227.     size        :Size of the sample that is being loaded (in bytes)
  228. */
  229. {
  230.     // Allocate GUS dram and store the address in Ultra[samplenr]
  231.  
  232.     // Alloc 1 byte more for anticlick measures. see below.
  233.  
  234.     if(UltraMemAlloc(ssize+1,&Ultra[samplenr])!=ULTRA_OK)
  235.         return 0;
  236.  
  237.     // Load the sample
  238.  
  239.     if(UltraFileload(fp,DMA_8|DMA_NO_CVT,Ultra[samplenr],ssize)!=ssize)
  240.         return 0;
  241.  
  242.     if(ml_samples[samplenr].replen>2){    // looping sample ?
  243.  
  244.         /*    Anticlick for looping samples:
  245.             Copy the first byte in the loop
  246.             one place beyond the end of the loop */
  247.  
  248.         UltraPoke(Ultra[samplenr]+ml_samples[samplenr].reppos+ml_samples[samplenr].replen,
  249.                   UltraPeek(Ultra[samplenr]+ml_samples[samplenr].reppos));
  250.     }
  251.     else{
  252.  
  253.         /*     Anticlick for one-shot samples:
  254.             Zero the byte beyond the end of the sample.
  255.         */
  256.  
  257.         UltraPoke(Ultra[samplenr]+ssize,0);
  258.     }
  259.  
  260.     return 1;
  261. }
  262.  
  263.  
  264.  
  265.  
  266. void PlayMod(char *file)
  267. {
  268.     int t;
  269.  
  270.     /* Tell MODLOAD to use 'MyLoader'
  271.        as the sample loader */
  272.  
  273.     ML_RegisterSampleLoader(MyLoader);
  274.  
  275.     // Load the module and convert the patterninfo
  276.  
  277.     if(!ML_LoadModule(file,NULL)){
  278.         printf("Error loading module %s: %s.\n",file,ml_errlist[ml_errno]);
  279.         return;
  280.     }
  281.  
  282.     printf("Title     : %s\n"
  283.            "ModType   : %s %d channels\n"
  284.            "Patterns  : %d\n"
  285.            "Songlength: %d\n",ml_songname,ml_modtype,ml_numchn,ml_numpat,ml_songlength);
  286.  
  287.  
  288. /*    Uncomment this if you want to see the samplenames.
  289.  
  290.     for(t=0;t<31;t++){
  291.         printf("Sample %d:%s\n",t,ml_samples[t].samplename);
  292.     }
  293. */
  294.  
  295.     for(t=0;t<ml_numchn;t++) UltraSetBalance(t,7+t-(ml_numchn>>1));
  296.  
  297.     // Let's make some noise !
  298.  
  299.     UltraEnableOutput();
  300.     SetBPM(125);            // Kickstart the timer
  301.  
  302.     printf("Press any key to stop playing...");
  303.  
  304.     // You might want to do something more useful here
  305.  
  306.     getch();
  307.  
  308.     UltraStopTimer(1);
  309. }
  310.  
  311.  
  312.  
  313. int main(int argc,char *argv[])
  314. {
  315.     printf("MIKMOD v0.2 or how to make a modplayer using the GUS SDK Toolkit v2.01\n"
  316.            "Programmed by MikMak of Unicorn Design. This is SOURCEWARE/PUBLIC DOMAIN\n"
  317.            "So you may use my routines as long as you mention my name :)\n"
  318.            "E-Mail: mikmak@stack.urc.tue.nl\n\n");
  319.  
  320.     if(argc!=2){
  321.         puts("Usage: MIKMOD <modname.mod>");
  322.         return -1;
  323.     }
  324.  
  325.     /* Get the ULTRASND environment string parameters */
  326.  
  327.     if(!UltraGetCfg(&config)){
  328.         puts("Ultrasound env. string not found..");
  329.         return -1;
  330.     }
  331.  
  332.     /* Set up max. 14 channels */
  333.  
  334.     if(UltraOpen(&config,14)==NO_ULTRA){
  335.         printf("No ultrasound card found\n");
  336.         return -1;
  337.     }
  338.  
  339.     /* Report size of GUS DRAM */
  340.  
  341.     printf("This GUS has %dK of Dram\n",UltraSizeDram());
  342.  
  343.     /* Grab the 80 microsecond timer handler */
  344.  
  345.     UltraTimer1Handler(HandleTimer1);
  346.  
  347.     /* Then try to play the module yeah */
  348.  
  349.     PlayMod(argv[1]);
  350.  
  351.     /* Shut sound down & re-init hardware ... */
  352.  
  353.     UltraClose();
  354.  
  355.     return 0;
  356. }
  357.  
  358.